home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / interapplication comm / menuscripter / sources / msaccessors.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  45.7 KB  |  1,688 lines

  1. // MSAEAccessors.c
  2. //
  3. // Original version by Jon Lansdell and Nigel Humphreys.
  4. // 4.0 and 3.1 updates by Greg Sutton.
  5. // ©Apple Computer Inc 1996, all rights reserved.
  6.  
  7. /*
  8.     Changes for 3.1
  9.  
  10.     14-Nov-95 : GS : Removed reliance on compiler setting local variable to zero
  11.                         in WindowFormAbsolutePosition() and TextFormAbsolutePosition().
  12.  
  13.     Changes for 4.0
  14.  
  15.     29-Feb-96 : GS : Added differentiation between windows and documents.
  16.     29-Feb-96 : GS : Added resolution of menus and menu items.
  17. */
  18.  
  19. #include "MSAccessors.h"
  20.  
  21. #include <Menus.h>
  22. #ifdef THINK_C
  23.     #include "PLStrs.h"
  24. #else
  25.     #include <PLStringFuncs.h>
  26. #endif
  27. #include <Scrap.h>
  28. #include <TextEdit.h>
  29. #include <AEObjects.h>
  30. #include <AEPackObject.h>
  31. #include <AERegistry.h>
  32. #include "MSGlobals.h"
  33. #include "MSUtils.h"
  34. #include "MSAEUtils.h"
  35. #include "MSWindow.h"
  36. #include "MSFile.h"
  37. #include "MSAppleEvents.h"
  38.  
  39. #include "MSToken.h"
  40. #include "MSAETextUtils.h"
  41. #include "MSAEWindowUtils.h"
  42. #include "MSAEMenuUtils.h"
  43.  
  44.  
  45. #pragma segment AppleEvent
  46.  
  47. // Install accessors that are used when AEResolve is called to convert
  48. // object specifiers into internal representations (tokens).
  49.  
  50. OSErr    InstallAccessors(void)
  51. {
  52.     OSErr    err;
  53.  
  54.     err = AEInstallObjectAccessor(cApplication, typeNull,            NewOSLAccessorProc(ApplicationFromNullAccessor), 0, false);
  55.     err = AEInstallObjectAccessor(cWindow,      typeNull,            NewOSLAccessorProc(WindowFromNullAccessor), 0, false);
  56.     err = AEInstallObjectAccessor(cDocument,    typeNull,            NewOSLAccessorProc(DocumentFromNullAccessor), 0, false);
  57.     err = AEInstallObjectAccessor(cProperty,    typeNull,             NewOSLAccessorProc(PropertyFromNullAccessor), 0, false);
  58.     err = AEInstallObjectAccessor(cMenu,        typeNull,             NewOSLAccessorProc(MenuFromNullAccessor), 0, false);
  59.  
  60.     err = AEInstallObjectAccessor(cWindow,      typeMyAppl,            NewOSLAccessorProc(WindowFromNullAccessor), 0, false);
  61.     err = AEInstallObjectAccessor(cDocument,    typeMyAppl,            NewOSLAccessorProc(DocumentFromNullAccessor), 0, false);
  62.     err = AEInstallObjectAccessor(cProperty,    typeMyAppl,         NewOSLAccessorProc(PropertyFromApplAccessor), 0, false);
  63.     err = AEInstallObjectAccessor(cMenu,        typeMyAppl,         NewOSLAccessorProc(MenuFromNullAccessor), 0, false);
  64.  
  65.     err = AEInstallObjectAccessor(cProperty,    typeMyWndw,            NewOSLAccessorProc(PropertyFromWndwAccessor), 0, false);
  66.  
  67.             // Handle text from a window
  68.             // e.g. some character of last document
  69.     err = AEInstallObjectAccessor(cInsertionPoint,typeMyDocument,    NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  70.     err = AEInstallObjectAccessor(cChar,        typeMyDocument,        NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  71.     err = AEInstallObjectAccessor(cText,         typeMyDocument,        NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  72.     err = AEInstallObjectAccessor(cWord,        typeMyDocument,        NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  73.     err = AEInstallObjectAccessor(cParagraph,    typeMyDocument,        NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  74.     err = AEInstallObjectAccessor(cProperty,    typeMyDocument,        NewOSLAccessorProc(PropertyFromDocumentAccessor), 0, false);
  75.  
  76.             // Handle text items within text items
  77.             // e.g. last word of first paragraph of front document
  78.     err = AEInstallObjectAccessor(cInsertionPoint,typeMyText,        NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  79.     err = AEInstallObjectAccessor(cChar,        typeMyText,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  80.     err = AEInstallObjectAccessor(cText,         typeMyText,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  81.     err = AEInstallObjectAccessor(cWord,        typeMyText,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  82.     err = AEInstallObjectAccessor(cParagraph,    typeMyText,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  83.     err = AEInstallObjectAccessor(cProperty,    typeMyText,            NewOSLAccessorProc(PropertyFromTextAccessor), 0, false);
  84.  
  85.             // Menus
  86.     err = AEInstallObjectAccessor(cMenuItem,    typeMyMenu,         NewOSLAccessorProc(MenuItemFromMenuAccessor), 0, false);
  87.     err = AEInstallObjectAccessor(cProperty,    typeMyMenu,         NewOSLAccessorProc(PropertyFromMenuAccessor), 0, false);
  88.  
  89.             // Menu Items
  90.     err = AEInstallObjectAccessor(cProperty,    typeMyMenuItem,     NewOSLAccessorProc(PropertyFromMenuItemAccessor), 0, false);
  91.  
  92.             // Handle text items from lists (of hopefully text items) also
  93.             //  e.g. every word of every paragraph of front document
  94.             //  or even - every word of every character of every paragraph of front document
  95.     err = AEInstallObjectAccessor(cInsertionPoint,typeAEList,        NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  96.     err = AEInstallObjectAccessor(cChar,         typeAEList,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  97.     err = AEInstallObjectAccessor(cText,         typeAEList,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  98.     err = AEInstallObjectAccessor(cWord,        typeAEList,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  99.     err = AEInstallObjectAccessor(cParagraph,    typeAEList,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  100.     err = AEInstallObjectAccessor(cProperty,    typeAEList,         NewOSLAccessorProc(PropertyFromListAccessor), 0, false);
  101.  
  102.  
  103.             // This is for 'select insertion point before contents of document 1'
  104.     err = AEInstallObjectAccessor(cInsertionPoint,     typeMyWindowProp,    NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  105.  
  106.             // This accessor is for getting properties of window properties
  107.             //  e.g. font of contents of document 1
  108.             // Relies on ability to coerce from a window property to text
  109.             //  for certain properties.
  110.     err = AEInstallObjectAccessor(cProperty,     typeMyDocumentProp,    NewOSLAccessorProc(PropertyFromTextAccessor), 0, false);
  111.  
  112.     return(err);
  113. }
  114.  
  115.  
  116. // Given selectionData of formAbsolutePosition for a window this routine returns
  117. //  a WindowToken descriptor for specified window.
  118. //
  119. // e.g.    tell application "MenuScripter"
  120. //            window 1
  121. //            --first document
  122. //            --some window
  123. //            --every window
  124. //        end tell
  125.  
  126. OSErr    WindowFormAbsolutePosition(const AEDesc    *selectionData, AEDesc* result)
  127. {
  128.     AEDesc    itemDesc = {typeNull, NULL};
  129.     short    windowCount,
  130.             index;
  131.     OSErr    err;
  132.  
  133.     windowCount = CountWindows();
  134.     
  135.     if (! windowCount)
  136.         return(errAEIllegalIndex);
  137.     
  138.     if (typeAbsoluteOrdinal == selectionData->descriptorType)
  139.     {
  140.         err = noErr;
  141.     
  142.         switch (*(DescType *)*selectionData->dataHandle)
  143.         {
  144.             case kAEFirst:
  145.                 index = 1;
  146.                 break;
  147.     
  148.             case kAELast:
  149.                 index = windowCount;
  150.                 break;
  151.     
  152.             case kAEMiddle:
  153.                 index = (windowCount + 1) / 2;
  154.                 break;
  155.     
  156.             case kAEAny:
  157.                 index = (Random() % windowCount) + 1;
  158.                 break;
  159.     
  160.             case kAEAll:
  161.                 err = AECreateList(NULL, 0 , false, result);
  162.                 if (noErr != err) goto done;
  163.                 
  164.                 for (index = 1; index <= windowCount; index++)
  165.                 {
  166.                     err = GetDescOfNthWindow(index, &itemDesc);
  167.                     if (noErr != err) goto done;
  168.                     
  169.                     err = AEPutDesc(result, 0, &itemDesc);
  170.                     if (noErr != err) goto done;
  171.                     
  172.                     if (itemDesc.dataHandle)
  173.                         AEDisposeDesc(&itemDesc);
  174.                 }
  175.                 
  176.                 goto done;        // We have created our list descriptor
  177.                 break;            // so we can just tidy up and return.
  178.                 
  179.             default:
  180.                 err = errAETypeError;
  181.         }
  182.     }
  183.     else
  184.         err = GetIntegerFromDescriptor(selectionData, &index);
  185.  
  186.     if (noErr != err) goto done;
  187.     
  188.     if (index < 0)        // Handle negative indexes
  189.         index = windowCount + index + 1;
  190.         
  191.     if (index > windowCount || index <= 0)
  192.         err = errAEIllegalIndex;
  193.     else
  194.         err = GetDescOfNthWindow(index, result);
  195.  
  196. done:    
  197.     if (itemDesc.dataHandle)
  198.         AEDisposeDesc(&itemDesc);
  199.  
  200.     return(err);
  201. } // WindowFormAbsolutePosition
  202.  
  203.  
  204. // Given a formName descriptor in selectionData, this routine returns a
  205. // WindowToken descriptor for the window with that name.
  206. //
  207. // e.g.    tell application "MenuScripter"
  208. //            document "Untitled"
  209. //        end tell
  210.  
  211. OSErr    WindowFormName(const AEDesc    *selectionData, AEDesc* result)
  212. {
  213.     Str255        name;
  214.     OSErr        err;
  215.     
  216.                 // This tries to coerce it first
  217.     err = GetPStringFromDescriptor(selectionData, name);
  218.     if (noErr != err) goto done;
  219.  
  220.     err = GetDescOfNamedWindow(name, result);
  221.  
  222. done:
  223.     return(err);
  224. }
  225.  
  226.  
  227. // Get a WindowToken descriptor for a window or document object specifier
  228. // from NULL (or the application). Only handles formAbsolutePosition and formName
  229. //
  230. // e.g.    tell application "MenuScripter"
  231. //            window 1
  232. //            --first document
  233. //            --document "Untitled"
  234. //            --every window
  235. //        end tell
  236.  
  237. pascal OSErr    WindowFromNullAccessor(DescType            wantClass,
  238.                                         const AEDesc    *container,
  239.                                         DescType          containerClass,
  240.                                         DescType        form, 
  241.                                         const AEDesc    *selectionData,
  242.                                         AEDesc            *value,
  243.                                         long            theRefCon)
  244. {
  245. #ifdef __MWERKS__
  246.     #pragma unused(container,theRefCon)
  247. #endif
  248.  
  249.     OSErr       err;
  250.     
  251.         // Can only handle cWindow and cDocument
  252.     if ( wantClass != cWindow )
  253.         return errAEWrongDataType;
  254.         
  255.         // Can only handle typeNull and typeMyAppl
  256.     if ( containerClass != typeNull && containerClass != typeMyAppl )
  257.         return errAENoSuchObject;
  258.     
  259.     switch (form)
  260.     {
  261.         case formAbsolutePosition:
  262.             err = WindowFormAbsolutePosition(selectionData, value);
  263.             break;
  264.             
  265.         case formName:
  266.             err = WindowFormName(selectionData, value);
  267.             break;
  268.             
  269.         default:
  270.             err = errAEBadTestKey;
  271.     }
  272.             
  273.     return err;
  274. } // WindowFromNullAccessor
  275.  
  276.  
  277. OSErr    DocumentFormAbsolutePosition(const AEDesc    *selectionData, AEDesc* result)
  278. {
  279.     AEDesc    itemDesc = {typeNull, NULL};
  280.     short    aCount,
  281.             index;
  282.     OSErr    err;
  283.  
  284.     aCount = CountDocuments();
  285.     
  286.     if ( ! aCount )
  287.         return(errAEIllegalIndex);
  288.     
  289.     if ( typeAbsoluteOrdinal == selectionData->descriptorType )
  290.     {
  291.         err = noErr;
  292.     
  293.         switch (*(DescType *)*selectionData->dataHandle)
  294.         {
  295.             case kAEFirst:
  296.                 index = 1;
  297.                 break;
  298.     
  299.             case kAELast:
  300.                 index = aCount;
  301.                 break;
  302.     
  303.             case kAEMiddle:
  304.                 index = ( aCount + 1 ) / 2;
  305.                 break;
  306.     
  307.             case kAEAny:
  308.                 index = ( Random() % aCount ) + 1;
  309.                 break;
  310.     
  311.             case kAEAll:
  312.                 err = AECreateList( NULL, 0 , false, result );
  313.                 if (noErr != err) goto done;
  314.                 
  315.                 for ( index = 1; index <= aCount; index++ )
  316.                 {
  317.                     err = GetDescOfNthDocument( index, &itemDesc );
  318.                     if (noErr != err) goto done;
  319.                     
  320.                     err = AEPutDesc( result, 0, &itemDesc );
  321.                     if (noErr != err) goto done;
  322.                     
  323.                     (void)AEDisposeDesc( &itemDesc );
  324.                 }
  325.                 
  326.                 goto done;        // We have created our list descriptor
  327.                 break;            // so we can just tidy up and return.
  328.                 
  329.             default:
  330.                 err = errAETypeError;
  331.         }
  332.     }
  333.     else
  334.         err = GetIntegerFromDescriptor(selectionData, &index);
  335.  
  336.     if (noErr != err) goto done;
  337.     
  338.     if (index < 0)        // Handle negative indexes
  339.         index = aCount + index + 1;
  340.         
  341.     if (index > aCount || index <= 0)
  342.         err = errAEIllegalIndex;
  343.     else
  344.         err = GetDescOfNthDocument(index, result);
  345.  
  346. done:    
  347.     (void)AEDisposeDesc(&itemDesc);
  348.  
  349.     return(err);
  350. } // DocumentFormAbsolutePosition
  351.  
  352.  
  353. OSErr    DocumentFormName(const AEDesc *selectionData, AEDesc* result)
  354. {
  355.     Str255        name;
  356.     OSErr        err;
  357.     
  358.             // This tries to coerce it first
  359.     err = GetPStringFromDescriptor(selectionData, name);
  360.     if (noErr != err) goto done;
  361.  
  362.     err = GetDescOfNamedDocument(name, result);
  363.  
  364. done:
  365.     return(err);
  366. }
  367.  
  368.  
  369. pascal OSErr    DocumentFromNullAccessor(DescType            wantClass,
  370.                                             const AEDesc    *container,
  371.                                             DescType          containerClass,
  372.                                             DescType        form, 
  373.                                             const AEDesc    *selectionData,
  374.                                             AEDesc            *value,
  375.                                             long            theRefCon)
  376. {
  377. #ifdef __MWERKS__
  378.     #pragma unused (container,theRefCon)
  379. #endif
  380.  
  381.     OSErr       err;
  382.     
  383.         // Can only handle cWindow and cDocument
  384.     if ( wantClass != cDocument )
  385.         return errAEWrongDataType;
  386.         
  387.         // Can only handle typeNull and typeMyAppl
  388.     if ( containerClass != typeNull && containerClass != typeMyAppl )
  389.         return errAENoSuchObject;
  390.     
  391.     switch (form)
  392.     {
  393.         case formAbsolutePosition:
  394.             err = DocumentFormAbsolutePosition( selectionData, value );
  395.             break;
  396.             
  397.         case formName:
  398.             err = DocumentFormName( selectionData, value );
  399.             break;
  400.             
  401.         default:
  402.             err = errAEBadTestKey;
  403.     }
  404.             
  405.     return err;
  406. } // DocumentFromNullAccessor
  407.  
  408.  
  409. pascal OSErr   ApplicationFromNullAccessor(DescType        wantClass,
  410.                                             const AEDesc    *container,
  411.                                             DescType        containerClass,
  412.                                             DescType        form, 
  413.                                             const AEDesc    *selectionData,
  414.                                             AEDesc            *value,
  415.                                             long            theRefCon)
  416. {
  417. #ifdef __MWERKS__
  418.     #pragma unused(container,selectionData,theRefCon)
  419. #endif
  420.  
  421.     OSErr    myErr;
  422.     AppToken theApp;
  423.     AEDesc   resultDesc;
  424.     
  425.     value->dataHandle     = nil;
  426.     resultDesc.dataHandle = nil;
  427.     
  428.     /* 
  429.         should only be called with wantClass = cWindow and
  430.         with containerClass = typeNull.
  431.         Currently accept as either formName or formAbsolutePosition
  432.     */
  433.     
  434.     if ((wantClass != cApplication) || (containerClass != typeNull) ||
  435.           !((form == formName) || (form == formAbsolutePosition)))
  436.         return(errAEWrongDataType);
  437.     
  438.     if ((form == formName) || (form == formAbsolutePosition))
  439.     {
  440.         theApp.highLongOfPSN = 0;
  441.         theApp.lowLongOfPSN  = kCurrentProcess;
  442.     }
  443.         
  444.     myErr = AECreateDesc(typeMyAppl, (Ptr)&theApp, sizeof(theApp), value);
  445.             
  446.     return(myErr);
  447. }    /* ApplicationFromNullAccessor */
  448.  
  449.  
  450. // Given a formAbsolutePosition selectionData descriptor and a TextToken from
  451. // which to index from. This routine returns a TextToken descriptor for the
  452. // text specified.
  453. //
  454. // e.g.    tell application "MenuScripter"
  455. //            first word of window 1    -- window one will be dealt with in
  456. //                                    -- WindowFromNullAccessor().
  457. //            --some character of middle paragraph of last document
  458. //                                    -- container token will be a paragraph
  459. //        end tell
  460.  
  461. OSErr    TextFormAbsolutePosition(TextToken* containerToken, AEDesc* selectionData,
  462.                                                     DescType wantClass, AEDesc* result)
  463. {
  464.     DPtr        docPtr;
  465.     short        elementCount;
  466.     AEDesc        aDesc = {typeNull, NULL};
  467.     long        index;
  468.     OSErr        err;
  469.     
  470.     docPtr = DPtrFromWindowPtr(containerToken->tokenWindow);
  471.  
  472.     if (! docPtr)
  473.     {
  474.         err = errAENoSuchObject;
  475.         goto done;
  476.     }
  477.  
  478.     err = CountTextElements(docPtr->theText, containerToken->tokenOffset,
  479.                                 containerToken->tokenLength, wantClass, &elementCount);
  480.     if (noErr != err) goto done;
  481.  
  482.     if (typeAbsoluteOrdinal == selectionData->descriptorType)
  483.     {
  484.         err = noErr;
  485.     
  486.         switch (*(DescType *)*selectionData->dataHandle)
  487.         {
  488.             case kAEFirst:
  489.                 index = 1;
  490.                 break;
  491.     
  492.             case kAELast:
  493.                 index = elementCount;
  494.                 break;
  495.     
  496.             case kAEMiddle:
  497.                 index = (elementCount + 1) / 2;
  498.                 break;
  499.     
  500.             case kAEAny:
  501.                 index = (Random() % elementCount) + 1;
  502.                 break;
  503.     
  504.             case kAEAll:
  505.                 err = AECreateList(NULL, 0 , false, result);
  506.                 
  507.                 for (index = 1; index <= elementCount; index++)
  508.                 {
  509.                     if (noErr == (err = GetDescOfNthTextElement(index, wantClass,
  510.                                                                 containerToken, &aDesc)))
  511.                     {
  512.                         err = AEPutDesc(result, 0, &aDesc);
  513.                         AEDisposeDesc(&aDesc);
  514.                     }
  515.                 }
  516.                 goto done;        // Created our result - clean up and return
  517.                 break;
  518.     
  519.             default:
  520.                 err = errAETypeError;
  521.         }
  522.     }
  523.     else        // Try and get an index out of the descriptor
  524.         err = GetLongIntFromDescriptor(selectionData, &index);
  525.     
  526.     if (noErr != err) goto done;
  527.                     // kAEAll has already created it's list
  528.     err = GetDescOfNthTextElement(index, wantClass,            // Checks for negatives and
  529.                                 containerToken, result);    // out of range.
  530.                                         
  531. done:
  532.     if (aDesc.dataHandle)
  533.         AEDisposeDesc(&aDesc);
  534.  
  535.     return(err);
  536. }
  537.  
  538.  
  539. // Given a TextToken container and a formRange descriptor. This routine
  540. // creates a TextToken descriptor starting at the the beginning of the
  541. // first item in the range and ending at the end of the last item in the range.
  542. //
  543. // e.g.    tell application "MenuScripter"
  544. //            paragraphs 2 thru 3 of document 1
  545. //        end tell
  546.  
  547. OSErr    TextFormRange(TextToken* containerToken, AEDesc* selectionData,
  548.                                                     DescType wantClass, AEDesc* result)
  549. {
  550. #ifdef __MWERKS__
  551.     #pragma unused(wantClass)
  552. #endif
  553.  
  554.     AEDesc        selectionRecord = {typeNull, NULL};
  555.     TextToken    startToken,
  556.                 stopToken;
  557.     DescType    returnedType;
  558.     Size        actualSize;
  559.     OSErr        err;
  560.  
  561.         // coerce the selection data into an AERecord
  562.     err = AECoerceDesc(selectionData, typeAERecord, &selectionRecord);
  563.     if (noErr != err) goto done;
  564.     
  565.         // get the start object as a text token this will reenter
  566.         // TextElemFromTextAccessor() but as formAbsolutePosition via 
  567.         // our installed coercion handler CoerceObjToAnything()
  568.         // because the keyAERangeStart parameter is actually an object specifier.
  569.     err = AEGetKeyPtr(&selectionRecord, keyAERangeStart, typeMyText,
  570.                             &returnedType, (Ptr)&startToken, sizeof(startToken), &actualSize);
  571.     if (noErr != err) goto done;
  572.     
  573.         // now do the same for the stop object
  574.     err = AEGetKeyPtr(&selectionRecord, keyAERangeStop, typeMyText,
  575.                             &returnedType, (Ptr)&stopToken, sizeof(stopToken), &actualSize);
  576.     if (noErr != err) goto done;
  577.     
  578.     if (containerToken->tokenWindow != startToken.tokenWindow
  579.             || containerToken->tokenWindow != stopToken.tokenWindow)
  580.     {
  581.         err = errAECorruptData;        // or whatever
  582.         goto done;
  583.     }
  584.         
  585.         // Use startToken to create result descriptor
  586.     startToken.tokenLength = stopToken.tokenOffset + stopToken.tokenLength - startToken.tokenOffset;
  587.                                                          
  588.     err = AECreateDesc(typeMyText, (Ptr)&startToken, sizeof(startToken), result);
  589.  
  590. done:
  591.     if (selectionRecord.dataHandle)
  592.         AEDisposeDesc(&selectionRecord);
  593.  
  594.     return(err);
  595. }
  596.  
  597.  
  598. // Given a container TextToken and a formRelativePosition selectionData descriptor
  599. // this routine returns a TextToken descriptor to the reative wantClass object
  600. // specified.
  601. // This routine currently only handles relative positions for a wantClass
  602. // of cInsertionPoint.
  603. //
  604. // e.g.    tell application "MenuScripter"
  605. //            insertion point after word 5 of document 1
  606. //        end tell
  607.  
  608. OSErr    TextFormRelativePosition(TextToken* containerToken, AEDesc* selectionData,
  609.                                                     DescType wantClass, AEDesc* result)
  610. {
  611.     TextToken    aTextToken;
  612.     DescType     aPosition;
  613.     OSErr        err;
  614.     
  615.     aTextToken.tokenWindow = containerToken->tokenWindow;
  616.  
  617.     switch (wantClass)
  618.     {
  619.         case cInsertionPoint:
  620.             err = GetEnumeratedFromDescriptor(selectionData, &aPosition);
  621.             
  622.             switch (aPosition)
  623.             {
  624.                 case kAEPrevious:
  625.                 case kAEBefore:
  626.                 case kAEBeginning:
  627.                     // No change to offset - just 0 length now
  628.                     // containerToken.tokenOffset = containerToken.tokenOffset;
  629.                     aTextToken.tokenOffset = containerToken->tokenOffset;
  630.                     aTextToken.tokenLength = 0;
  631.                     break;
  632.             
  633.                 case kAENext:
  634.                 case kAEAfter:
  635.                 case kAEEnd:
  636.                     aTextToken.tokenOffset = containerToken->tokenOffset + containerToken->tokenLength;
  637.                     aTextToken.tokenLength = 0;
  638.                     break;
  639.                     
  640.                 default:
  641.                     err = errAEIllegalIndex;
  642.             }
  643.             break;
  644.             
  645.         default:
  646.             err = errAEWrongDataType;    // Could do cChar, cWord… but this is only a sample
  647.     }
  648.     
  649.     if (noErr != err) goto done;
  650.  
  651.     err = AECreateDesc(typeMyText, (Ptr)&aTextToken, sizeof(aTextToken), result);
  652.  
  653. done:
  654.     return(err);
  655. }
  656.  
  657.  
  658. // Tries to create a TextToken descriptor given a container which may
  659. // be a TextToken descriptor or a WindowToken descriptor. A
  660. // selectionData descriptor which can be of formAbsolutePosition,
  661. // formRange or formRelativePosition, and a wantClass which should
  662. // be cInsertionPoint, cChar, cText, cWord or cParagraph.
  663. //
  664. // e.g.    tell application "MenuScripter"
  665. //            first word of document 1 -- document 1 will go through WindowFromNullAccessor()
  666. //                                     -- which will return a WindowToken descriptor. This
  667. //                                     -- descriptor will then be coerced to a TextToken
  668. //                                     -- descriptor and used as the container.
  669. //        end tell
  670.  
  671. pascal OSErr    TextElemFromTextAccessor(DescType            wantClass,
  672.                                             AEDesc            *container,
  673.                                             DescType        containerClass,
  674.                                             DescType        form,
  675.                                             AEDesc            *selectionData,
  676.                                             AEDesc            *value,
  677.                                             long            theRefCon)
  678. {
  679. #ifdef __MWERKS__
  680.     #pragma unused(containerClass)
  681. #endif
  682.  
  683.     TextToken   containerToken;
  684.     long        index;
  685.     long        itemCount;
  686.     AEDesc        aDesc = {typeNull, NULL},
  687.                 resultDesc = {typeNull, NULL};
  688.     DescType    returnedType;
  689.     Size        actualSize;
  690.     OSErr       myErr;
  691.     
  692.                 // If it's a list then we need to call this accessor for every
  693.                 // item within the list (which could of course be more lists).
  694.     if (typeAEList == container->descriptorType)
  695.     {
  696.         myErr = AECreateList(NULL, 0 , false, value);    // Result will also be a list of items
  697.         if (noErr != myErr) goto done;
  698.         myErr = AECountItems(container, &itemCount);
  699.         if (noErr != myErr) goto done;
  700.  
  701.         for (index = 1; index <= itemCount; index++)    // Do in forward order
  702.         {
  703.             myErr = AEGetNthDesc(container, index, typeWildCard, &returnedType, &aDesc);
  704.  
  705.             if (noErr == myErr)        // Call this function recursively if necessary
  706.                 myErr = TextElemFromTextAccessor(wantClass, &aDesc, returnedType,
  707.                                             form, selectionData, &resultDesc, theRefCon);
  708.             
  709.             if (noErr == myErr)        // Add item to the end of our list
  710.                 myErr = AEPutDesc(value, 0, &resultDesc);
  711.             
  712.             if (aDesc.dataHandle)
  713.                 AEDisposeDesc(&aDesc);
  714.             if (resultDesc.dataHandle)
  715.                 AEDisposeDesc(&resultDesc);
  716.         }
  717.     }
  718.     else
  719.     {                // We have a coercion handler from document to text
  720.         myErr = AECoerceDesc(container, typeMyText, &aDesc);
  721.         if (noErr != myErr) goto done;
  722.  
  723.                 // Get the containing TextToken
  724.         GetRawDataFromDescriptor(&aDesc, (Ptr)&containerToken, sizeof(containerToken), &actualSize);
  725.         
  726.         switch (form)
  727.         {
  728.             case formAbsolutePosition:
  729.                 myErr = TextFormAbsolutePosition(&containerToken, selectionData,
  730.                                                                     wantClass, value);
  731.                 break;                                        
  732.                 
  733.             case formRange:
  734.                 myErr = TextFormRange(&containerToken, selectionData,
  735.                                                             wantClass, value);
  736.                 break;
  737.                 
  738.             case formRelativePosition:
  739.                 myErr = TextFormRelativePosition(&containerToken, selectionData,
  740.                                                                 wantClass, value);
  741.                 break;
  742.                 
  743.             default:
  744.                 myErr = errAEBadKeyForm;
  745.         }
  746.     }
  747.  
  748. done:
  749.     if (aDesc.dataHandle)
  750.         AEDisposeDesc(&aDesc);
  751.         
  752.     return(myErr);
  753. }    // TextElemFromTextAccessor
  754.  
  755.  
  756. // Given a TextToken descriptor as a container convert this into 
  757. // a TextPropToken descriptor for the property.
  758.  
  759. pascal OSErr    PropertyFromTextAccessor(DescType            wantClass,
  760.                                             const AEDesc    *container,
  761.                                             DescType        containerClass,
  762.                                             DescType        form, 
  763.                                             const AEDesc    *selectionData,
  764.                                             AEDesc            *value,
  765.                                             long            theRefCon)
  766. {
  767. #ifdef __MWERKS__
  768.     #pragma unused (theRefCon, containerClass)
  769. #endif
  770.  
  771.     AEDesc            textDesc = {typeNull, NULL},
  772.                     propertyDesc = {typeNull, NULL};
  773.     Size            actualSize;
  774.     TextToken        aTextToken;
  775.     TextPropToken    aTextPropToken;
  776.     DescType        aProperty;
  777.     OSErr            err;
  778.     
  779.     if (cProperty != wantClass || formPropertyID != form)
  780.         return(errAEWrongDataType);
  781.         
  782.                 // Try and coerce to a TextToken descriptor
  783.     err = AECoerceDesc(container, typeMyText, &textDesc);
  784.     if (noErr != err) goto done;
  785.     
  786.                 // Get the TextToken
  787.     GetRawDataFromDescriptor(&textDesc, (Ptr)&aTextToken,
  788.                             sizeof(aTextToken), &actualSize);
  789.             
  790.                 // Make sure the selection data is typeType
  791.     err = AECoerceDesc(selectionData, typeType, &propertyDesc);
  792.     if (noErr != err) goto done;
  793.  
  794.                 // Get the property
  795.     GetRawDataFromDescriptor(&propertyDesc, (Ptr)&aProperty,
  796.                                     sizeof(aProperty),  &actualSize);
  797.             
  798.                 //    Combine the two into single token
  799.     aTextPropToken.tokenTextToken = aTextToken;
  800.     aTextPropToken.tokenProperty  = aProperty;
  801.     
  802.     err = AECreateDesc(typeMyTextProp, (Ptr)&aTextPropToken,
  803.                                 sizeof(aTextPropToken), value);
  804.  
  805. done:        
  806.     (void)AEDisposeDesc(&textDesc);
  807.     (void)AEDisposeDesc(&propertyDesc);
  808.         
  809.     return(err);
  810. } // PropertyFromTextAccessor
  811.  
  812.  
  813. // Given a WindowToken descriptor as a container convert this into 
  814. // a WindowPropToken descriptor for the property.
  815.  
  816. pascal OSErr    PropertyFromWndwAccessor(DescType            wantClass,
  817.                                             AEDesc            *container,
  818.                                             DescType        containerClass,
  819.                                             DescType        form, 
  820.                                             AEDesc            *selectionData,
  821.                                             AEDesc            *value,
  822.                                             long            theRefCon)
  823. {
  824. #ifdef __MWERKS__
  825.     #pragma unused(containerClass)
  826. #endif
  827.  
  828.     long                itemCount,
  829.                         index;
  830.     AEDesc                resultDesc = {typeNull, NULL},
  831.                         windowDesc = {typeNull, NULL},
  832.                         propDesc = {typeNull, NULL};
  833.     Size                actualSize;
  834.     DescType            returnedType;
  835.     WindowToken         theWindowToken;
  836.     WindowPropToken     myWindowProp;
  837.     OSErr               err;
  838.     
  839.     if (typeAEList == container->descriptorType)
  840.     {
  841.         err = AECreateList(NULL, 0 , false, value);        // Result will also be a list of items
  842.         if (noErr != err) goto done;
  843.         err = AECountItems(container, &itemCount);
  844.         if (noErr != err) goto done;
  845.     
  846.         for (index = 1; index <= itemCount; index++)    // Do in forward order
  847.         {
  848.             err = AEGetNthDesc(container, index, typeWildCard, &returnedType, &windowDesc);
  849.     
  850.             if (noErr == err)                            // Recursively call this routine
  851.                                                         // - could be another list.
  852.                 err = PropertyFromWndwAccessor(wantClass, &windowDesc, windowDesc.descriptorType,
  853.                                                         form, selectionData, &resultDesc, theRefCon);
  854.             
  855.             if (noErr == err)                            // Add item to the end of our list
  856.                 err = AEPutDesc(value, 0, &resultDesc);
  857.             
  858.             if (windowDesc.dataHandle)
  859.                 AEDisposeDesc(&windowDesc);
  860.             if (resultDesc.dataHandle)
  861.                 AEDisposeDesc(&resultDesc);
  862.         }
  863.     }
  864.     else
  865.     {        // get the window token - it's the container
  866.         
  867.         err = AECoerceDesc(container, typeMyWndw, &windowDesc);
  868.         GetRawDataFromDescriptor(&windowDesc, (Ptr)&theWindowToken,
  869.                                         sizeof(theWindowToken), &actualSize);
  870.                                                             
  871.             // Check the window exists
  872.         
  873.         if (theWindowToken.tokenWindow == NULL)
  874.             err = errAEIllegalIndex;
  875.         else
  876.         {        // get the property - it's in the selection data
  877.             
  878.             err = AECoerceDesc(selectionData, typeType, &propDesc);
  879.             GetRawDataFromDescriptor(&propDesc, (Ptr)&returnedType,
  880.                                             sizeof(returnedType), &actualSize);
  881.             
  882.                 // Combine the two into single token
  883.  
  884.             myWindowProp.tokenWindowToken = theWindowToken;
  885.             myWindowProp.tokenProperty    = returnedType;
  886.             
  887.             err = AECreateDesc(typeMyWindowProp, (Ptr)&myWindowProp,
  888.                                                 sizeof(myWindowProp), value);
  889.         }
  890.     }
  891.     
  892. done:
  893.     if (windowDesc.dataHandle)
  894.         AEDisposeDesc(&windowDesc);
  895.     if (propDesc.dataHandle)
  896.         AEDisposeDesc(&propDesc);
  897.     if (resultDesc.dataHandle)
  898.         AEDisposeDesc(&resultDesc);
  899.         
  900.     return(err);
  901. } // PropertyFromWndwAccessor
  902.  
  903.  
  904. pascal OSErr    PropertyFromDocumentAccessor(DescType            wantClass,
  905.                                                 AEDesc            *container,
  906.                                                 DescType        containerClass,
  907.                                                 DescType        form, 
  908.                                                 AEDesc            *selectionData,
  909.                                                 AEDesc            *value,
  910.                                                 long            theRefCon)
  911. {
  912. #ifdef __MWERKS__
  913.     #pragma unused(containerClass)
  914. #endif
  915.  
  916.     long                itemCount,
  917.                         index;
  918.     AEDesc                resultDesc = {typeNull, NULL},
  919.                         windowDesc = {typeNull, NULL},
  920.                         propDesc = {typeNull, NULL};
  921.     Size                actualSize;
  922.     DescType            returnedType;
  923.     WindowToken         theWindowToken;
  924.     WindowPropToken     myWindowProp;
  925.     OSErr               err;
  926.     
  927.     if (typeAEList == container->descriptorType)
  928.     {
  929.         err = AECreateList(NULL, 0 , false, value);        // Result will also be a list of items
  930.         if (noErr != err) goto done;
  931.         err = AECountItems(container, &itemCount);
  932.         if (noErr != err) goto done;
  933.     
  934.         for (index = 1; index <= itemCount; index++)    // Do in forward order
  935.         {
  936.             err = AEGetNthDesc(container, index, typeWildCard, &returnedType, &windowDesc);
  937.     
  938.             if (noErr == err)                            // Recursively call this routine
  939.                                                         // - could be another list.
  940.                 err = PropertyFromDocumentAccessor(wantClass, &windowDesc, windowDesc.descriptorType,
  941.                                                         form, selectionData, &resultDesc, theRefCon);
  942.             
  943.             if (noErr == err)                            // Add item to the end of our list
  944.                 err = AEPutDesc(value, 0, &resultDesc);
  945.             
  946.             (void)AEDisposeDesc(&windowDesc);
  947.             (void)AEDisposeDesc(&resultDesc);
  948.         }
  949.     }
  950.     else
  951.     {        // get the window token - it's the container
  952.         
  953.         err = AECoerceDesc(container, typeMyDocument, &windowDesc);
  954.         GetRawDataFromDescriptor(&windowDesc, (Ptr)&theWindowToken,
  955.                                         sizeof(theWindowToken), &actualSize);
  956.                                                             
  957.             // Check the window exists
  958.         
  959.         if (theWindowToken.tokenWindow == NULL)
  960.             err = errAEIllegalIndex;
  961.         else
  962.         {        // get the property - it's in the selection data
  963.             
  964.             err = AECoerceDesc(selectionData, typeType, &propDesc);
  965.             GetRawDataFromDescriptor(&propDesc, (Ptr)&returnedType,
  966.                                             sizeof(returnedType), &actualSize);
  967.             
  968.                 // Combine the two into single token
  969.  
  970.             myWindowProp.tokenWindowToken = theWindowToken;
  971.             myWindowProp.tokenProperty    = returnedType;
  972.             
  973.             err = AECreateDesc(typeMyDocumentProp, (Ptr)&myWindowProp,
  974.                                                 sizeof(myWindowProp), value);
  975.         }
  976.     }
  977.     
  978. done:
  979.     (void)AEDisposeDesc(&windowDesc);
  980.     (void)AEDisposeDesc(&propDesc);
  981.     (void)AEDisposeDesc(&resultDesc);
  982.         
  983.     return(err);
  984. } // PropertyFromDocumentAccessor
  985.  
  986.  
  987. pascal OSErr    PropertyFromNullAccessor(DescType            wantClass,
  988.                                             AEDesc            *container,
  989.                                             DescType        containerClass,
  990.                                             DescType        form, 
  991.                                             AEDesc            *selectionData,
  992.                                             AEDesc            *value,
  993.                                             long            theRefCon)
  994. {
  995. #ifdef __MWERKS__
  996.     #pragma unused (container, containerClass)
  997. #endif
  998.  
  999.     AEDesc        aDesc = {typeNull, NULL};
  1000.     OSErr        err;
  1001.  
  1002.     if ((wantClass != cProperty) || (form != formPropertyID))
  1003.         return(errAEWrongDataType);
  1004.  
  1005.     switch (*(DescType *)*selectionData->dataHandle)
  1006.     {
  1007.         case pSelection:    // The selection defaults to the front window
  1008.                             // selection.
  1009.             err = GetDescOfNthDocument( 1, &aDesc );    // Disposed of at end
  1010.             if (noErr != err) goto done;
  1011.             err = PropertyFromDocumentAccessor(wantClass, &aDesc, typeMyDocument, form, 
  1012.                                                     selectionData, value, theRefCon);
  1013.             break;
  1014.             
  1015.         default:            // Otherwise try an application property - it is fron NULL
  1016.             err = PropertyFromApplAccessor(wantClass, &aDesc, typeMyWndw, form, 
  1017.                                                     selectionData, value, theRefCon);
  1018.     }
  1019.     
  1020. done:
  1021.     (void)AEDisposeDesc( &aDesc );
  1022.     
  1023.     return err;
  1024. }
  1025.  
  1026.  
  1027. // Convert a list of Token descriptors to a list of Property Token descriptors.
  1028. // Only TextTokens and WindowTokens are supported in this version.
  1029.  
  1030. OSErr    TokenListToPropertyList(AEDesc* tokenList, DescType aProperty, AEDesc* result)
  1031. {
  1032.     AEDesc                aDesc = {typeNull, NULL},
  1033.                         resultDesc = {typeNull, NULL};
  1034.     DescType            returnedType;
  1035.     long                itemCount,
  1036.                         index;
  1037.     WindowPropToken        aWindowPropToken;
  1038.     TextPropToken        aTextPropToken;
  1039.     Size                actualSize;
  1040.     OSErr                err;
  1041.  
  1042.     err = AECreateList(NULL, 0 , false, result);        // Result will also be a list of items
  1043.     if (noErr != err) goto done;
  1044.     err = AECountItems(tokenList, &itemCount);        // Will return an error if not of type typeAEList
  1045.     if (noErr != err) goto done;
  1046.  
  1047.     for (index = 1; index <= itemCount; index++)    // Do in forward order
  1048.     {
  1049.         err = AEGetNthDesc(tokenList, index, typeWildCard, &returnedType, &aDesc);
  1050.  
  1051.         if (noErr == err)                            // Create appropriate property token
  1052.             switch (aDesc.descriptorType)
  1053.             {
  1054.                 case typeMyWndw:
  1055.                     GetRawDataFromDescriptor(&aDesc, (Ptr)&aWindowPropToken,
  1056.                                                     sizeof(WindowToken), &actualSize);
  1057.                     aWindowPropToken.tokenProperty = aProperty;
  1058.                     err = AECreateDesc(typeMyWindowProp, (Ptr)&aWindowPropToken,
  1059.                                                     sizeof(aWindowPropToken), &resultDesc);
  1060.                     break;
  1061.                     
  1062.                 case typeMyText:
  1063.                     GetRawDataFromDescriptor(&aDesc, (Ptr)&aTextPropToken,
  1064.                                                     sizeof(TextToken), &actualSize);
  1065.                     aTextPropToken.tokenProperty = aProperty;
  1066.                     err = AECreateDesc(typeMyTextProp, (Ptr)&aTextPropToken,
  1067.                                                     sizeof(aTextPropToken), &resultDesc);
  1068.                     break;
  1069.                     
  1070.                 case typeAEList:                    // Recursive call if a list
  1071.                     err = TokenListToPropertyList(&aDesc, aProperty, &resultDesc);
  1072.                     break;
  1073.                     
  1074.                 default:        // May already be a property token
  1075.                     err = errAEBadListItem;
  1076.             }
  1077.         
  1078.         if (noErr == err)        // Add item to the end of our list
  1079.             err = AEPutDesc(result, 0, &resultDesc);
  1080.         
  1081.         if (aDesc.dataHandle)
  1082.             AEDisposeDesc(&aDesc);
  1083.         if (resultDesc.dataHandle)
  1084.             AEDisposeDesc(&resultDesc);
  1085.             
  1086.         err = noErr;            // Try and do all the items we can in the list
  1087.     }
  1088.             
  1089. done:
  1090.     return(err);
  1091. }
  1092.  
  1093.  
  1094. // Given a container that is a list of Token descriptors, this routine
  1095. // returns a list of PropToken descriptors.
  1096.  
  1097. pascal OSErr    PropertyFromListAccessor(DescType            wantClass,
  1098.                                             AEDesc            *container,
  1099.                                             DescType        containerClass,
  1100.                                             DescType        form, 
  1101.                                             AEDesc            *selectionData,
  1102.                                             AEDesc            *value,
  1103.                                             long            theRefCon)
  1104. {
  1105. #ifdef __MWERKS__
  1106.     #pragma unused(containerClass, theRefCon)
  1107. #endif
  1108.  
  1109.     OSErr        err;
  1110.     
  1111.     if (wantClass != cProperty && form != formPropertyID)
  1112.         return(errAEBadKeyForm);
  1113.     
  1114.     err = TokenListToPropertyList(container, *(DescType *)*selectionData->dataHandle, value);
  1115.  
  1116.     return(err);
  1117. }
  1118.  
  1119.  
  1120. // Given a AppToken descriptor as a container convert this into 
  1121. // a WindowPropToken descriptor for the property.
  1122.  
  1123. pascal OSErr    PropertyFromApplAccessor(DescType            wantClass,
  1124.                                             const AEDesc    *container,
  1125.                                             DescType        containerClass,
  1126.                                             DescType        form, 
  1127.                                             const AEDesc    *selectionData,
  1128.                                             AEDesc            *value,
  1129.                                             long            theRefCon)
  1130. {
  1131. #ifdef __MWERKS__
  1132.     #pragma unused (theRefCon, containerClass)
  1133. #endif
  1134.  
  1135.     OSErr         myErr;
  1136.     OSErr         ignoreErr;
  1137.     AppToken      theApplToken;
  1138.     DescType      theProperty;
  1139.     AEDesc        applDesc;
  1140.     AEDesc        propDesc;
  1141.     Size          actualSize;
  1142.     AppPropToken myApplProp;
  1143.         
  1144.     value->dataHandle     = nil;
  1145.     applDesc.dataHandle   = nil;
  1146.     propDesc.dataHandle   = nil;
  1147.     
  1148.     if ((wantClass != cProperty) ||
  1149.           (form != formPropertyID))
  1150.     {
  1151.         return(errAEWrongDataType);
  1152.     }
  1153.     
  1154.     // get the application token - it's the container
  1155.     
  1156.     myErr = AECoerceDesc(container, typeMyAppl, &applDesc);
  1157.     GetRawDataFromDescriptor(&applDesc, (Ptr)&theApplToken,
  1158.                                 sizeof(theApplToken), &actualSize);
  1159.             
  1160.     // get the property - it's in the selection data
  1161.     
  1162.     myErr = AECoerceDesc(selectionData, typeType, &propDesc);
  1163.     GetRawDataFromDescriptor(&propDesc, (Ptr)&theProperty,
  1164.                                 sizeof(theProperty), &actualSize);
  1165.  
  1166.     //    Combine the two into single token
  1167.  
  1168.     myApplProp.tokenAppToken = theApplToken;
  1169.     myApplProp.tokenProperty = theProperty;
  1170.     
  1171.     myErr = AECreateDesc(typeMyApplProp, (Ptr)&myApplProp,
  1172.                                         sizeof(myApplProp), value);
  1173.         
  1174.     if (applDesc.dataHandle)
  1175.         ignoreErr = AEDisposeDesc(&applDesc);
  1176.         
  1177.     if (propDesc.dataHandle)
  1178.         ignoreErr = AEDisposeDesc(&propDesc);
  1179.         
  1180.     return(myErr);
  1181. } // PropertyFromApplAccessor
  1182.  
  1183.  
  1184. pascal OSErr    PropertyFromWinPropertyAccessor(DescType        wantClass,
  1185.                                                 const AEDesc    *container,
  1186.                                                 DescType        containerClass,
  1187.                                                 DescType        form, 
  1188.                                                 const AEDesc    *selectionData,
  1189.                                                 AEDesc            *value,
  1190.                                                 long            theRefCon)
  1191. {
  1192. #ifdef __MWERKS__
  1193.     #pragma unused(wantClass, containerClass, form, theRefCon)
  1194. #endif
  1195.  
  1196.     OSErr           myErr;
  1197.     OSErr           ignoreErr;
  1198.     WindowPropToken theWindowPropToken;
  1199.     AEDesc          newDesc, propDesc;
  1200.     Size            tokenSize;
  1201.     DPtr            theDocument;
  1202.     TextToken       theTextToken;
  1203.     DescType        theProperty;
  1204.     Size            actualSize;
  1205.     TextPropToken   myTextProp;
  1206.     
  1207.     // the container is a window property token. Get the token for this
  1208.     // and check that it is valid to get a property of this property
  1209.     
  1210.     myErr = AECoerceDesc(container, typeMyWindowProp, &newDesc);
  1211.     
  1212.     if (myErr)
  1213.      return(myErr);
  1214.  
  1215.     GetRawDataFromDescriptor(&newDesc, (Ptr)&theWindowPropToken,
  1216.                                 sizeof(theWindowPropToken), &tokenSize);
  1217.                                                      
  1218.     // if the property is pSelection, we then want to convert this to a text token
  1219.     // and then return a text property token
  1220.     
  1221.     if (theWindowPropToken.tokenProperty == pSelection) 
  1222.     {
  1223.         theDocument = DPtrFromWindowPtr(theWindowPropToken.tokenWindowToken.tokenWindow);
  1224.         
  1225.         // build a text token to represent the selection
  1226.         theTextToken.tokenOffset = (**(theDocument->theText)).selStart + 1;
  1227.         theTextToken.tokenLength = ((**(theDocument->theText)).selEnd -
  1228.                                    (**(theDocument->theText)).selStart) -1;
  1229.         theTextToken.tokenWindow = theWindowPropToken.tokenWindowToken.tokenWindow;
  1230.         
  1231.     
  1232.         // now get the property- it's in the selection data
  1233.         myErr = AECoerceDesc(selectionData, typeType, &propDesc);
  1234.         GetRawDataFromDescriptor(&propDesc, (Ptr)&theProperty,
  1235.                                         sizeof(theProperty), &actualSize);
  1236.         
  1237.         // Combine the two into single token
  1238.         myTextProp.tokenTextToken = theTextToken;
  1239.         myTextProp.tokenProperty  = theProperty;
  1240.  
  1241.           myErr = AECreateDesc(typeMyTextProp,(Ptr)&myTextProp,
  1242.                                          sizeof(myTextProp),value);
  1243.                                          
  1244.                                          
  1245.       if (propDesc.dataHandle) ignoreErr = AEDisposeDesc(&propDesc);
  1246.         if (newDesc.dataHandle)  ignoreErr = AEDisposeDesc(&newDesc);
  1247.  
  1248.       return myErr;
  1249.                                                                                                   
  1250.     }
  1251.     
  1252.     if (newDesc.dataHandle) 
  1253.         ignoreErr = AEDisposeDesc(&newDesc);
  1254.     
  1255.     return errAEWrongDataType;
  1256. }
  1257.  
  1258.  
  1259. OSErr    MenuFormAbsolutePosition( const AEDesc *selectionData, AEDesc* result )
  1260. {
  1261.     AEDesc    itemDesc = {typeNull, NULL};
  1262.     short    aCount,
  1263.             index;
  1264.     OSErr    err;
  1265.  
  1266.     aCount = CountMenus();
  1267.     
  1268.     if (! aCount)
  1269.         return(errAEIllegalIndex);
  1270.     
  1271.     if ( typeAbsoluteOrdinal == selectionData->descriptorType )
  1272.     {
  1273.         err = noErr;
  1274.     
  1275.         switch (*(DescType *)*selectionData->dataHandle)
  1276.         {
  1277.             case kAEFirst:
  1278.                 index = 1;
  1279.                 break;
  1280.     
  1281.             case kAELast:
  1282.                 index = aCount;
  1283.                 break;
  1284.     
  1285.             case kAEMiddle:
  1286.                 index = (aCount + 1) / 2;
  1287.                 break;
  1288.     
  1289.             case kAEAny:
  1290.                 index = (Random() % aCount) + 1;
  1291.                 break;
  1292.     
  1293.             case kAEAll:
  1294.                 err = AECreateList(NULL, 0 , false, result);
  1295.                 if (noErr != err) goto done;
  1296.                 
  1297.                 for (index = 1; index <= aCount; index++)
  1298.                 {
  1299.                     err = GetDescOfNthMenu(index, &itemDesc);
  1300.                     if (noErr != err) goto done;
  1301.                     
  1302.                     err = AEPutDesc(result, 0, &itemDesc);
  1303.                     if (noErr != err) goto done;
  1304.                     
  1305.                     if (itemDesc.dataHandle)
  1306.                         AEDisposeDesc(&itemDesc);
  1307.                 }
  1308.                 
  1309.                 goto done;        // We have created our list descriptor
  1310.                 break;            // so we can just tidy up and return.
  1311.                 
  1312.             default:
  1313.                 err = errAETypeError;
  1314.         }
  1315.     }
  1316.     else
  1317.         err = GetIntegerFromDescriptor( selectionData, &index );
  1318.  
  1319.     if (noErr != err) goto done;
  1320.     
  1321.     if (index < 0)        // Handle negative indexes
  1322.         index = aCount + index + 1;
  1323.         
  1324.     if ( index > aCount || index <= 0 )
  1325.         err = errAEIllegalIndex;
  1326.     else
  1327.         err = GetDescOfNthMenu( index, result );
  1328.  
  1329. done:    
  1330.     (void)AEDisposeDesc( &itemDesc );
  1331.  
  1332.     return err;
  1333. } // MenuFormAbsolutePosition
  1334.  
  1335.  
  1336. OSErr    MenuFormName( const AEDesc *selectionData, AEDesc* result )
  1337. {
  1338.     Str255        name;
  1339.     OSErr        err;
  1340.     
  1341.             // This tries to coerce it first
  1342.     err = GetPStringFromDescriptor( selectionData, name );
  1343.     if ( noErr != err ) goto done;
  1344.  
  1345.     err = GetDescOfNamedMenu( name, result );
  1346.  
  1347. done:
  1348.     return(err);
  1349. }
  1350.  
  1351.  
  1352. pascal OSErr    MenuFromNullAccessor( DescType            wantClass,
  1353.                                         const AEDesc    *container,
  1354.                                         DescType          containerClass,
  1355.                                         DescType        form, 
  1356.                                         const AEDesc    *selectionData,
  1357.                                         AEDesc            *value,
  1358.                                         long            theRefCon)
  1359. {
  1360. #ifdef __MWERKS__
  1361.     #pragma unused (container,theRefCon)
  1362. #endif
  1363.  
  1364.     OSErr       err;
  1365.     
  1366.         // Can only handle cWindow and cDocument
  1367.     if ( wantClass != cMenu )
  1368.         return errAEWrongDataType;
  1369.         
  1370.         // Can only handle typeNull and typeMyAppl
  1371.     if ( containerClass != typeNull && containerClass != typeMyAppl )
  1372.         return errAENoSuchObject;
  1373.     
  1374.     switch (form)
  1375.     {
  1376.         case formAbsolutePosition:
  1377.             err = MenuFormAbsolutePosition( selectionData, value );
  1378.             break;
  1379.             
  1380.         case formName:
  1381.             err = MenuFormName( selectionData, value );
  1382.             break;
  1383.             
  1384.         default:
  1385.             err = errAEBadTestKey;
  1386.     }
  1387.             
  1388.     return err;
  1389. }
  1390.  
  1391.  
  1392. pascal OSErr    PropertyFromMenuAccessor(DescType            wantClass,
  1393.                                             AEDesc            *container,
  1394.                                             DescType        containerClass,
  1395.                                             DescType        form, 
  1396.                                             AEDesc            *selectionData,
  1397.                                             AEDesc            *value,
  1398.                                             long            theRefCon)
  1399. {
  1400. #ifdef __MWERKS__
  1401.     #pragma unused(containerClass)
  1402. #endif
  1403.  
  1404.     long                itemCount,
  1405.                         index;
  1406.     AEDesc                resultDesc = {typeNull, NULL},
  1407.                         aDesc = {typeNull, NULL},
  1408.                         propDesc = {typeNull, NULL};
  1409.     Size                actualSize;
  1410.     DescType            returnedType;
  1411.     MenuToken             theToken;
  1412.     MenuPropToken         thePropertyToken;
  1413.     OSErr               err;
  1414.     
  1415.     if (typeAEList == container->descriptorType)
  1416.     {
  1417.         err = AECreateList( NULL, 0 , false, value );    // Result will also be a list of items
  1418.         if (noErr != err) goto done;
  1419.         err = AECountItems( container, &itemCount );
  1420.         if (noErr != err) goto done;
  1421.     
  1422.         for ( index = 1; index <= itemCount; index++ )    // Do in forward order
  1423.         {
  1424.             err = AEGetNthDesc( container, index, typeWildCard, &returnedType, &aDesc );
  1425.             if ( noErr != err ) goto done;
  1426.                                                         // Recursively call this routine
  1427.                                                         // - could be another list.
  1428.             err = PropertyFromMenuAccessor( wantClass, &aDesc, aDesc.descriptorType,
  1429.                                                     form, selectionData, &resultDesc, theRefCon );
  1430.             
  1431.             err = AEPutDesc( value, 0, &resultDesc );    // Add item to the end of our list
  1432.             if ( noErr != err ) goto done;
  1433.             
  1434.             (void)AEDisposeDesc( &aDesc );
  1435.             (void)AEDisposeDesc( &resultDesc );
  1436.         }
  1437.     }
  1438.     else
  1439.     {        // get the window token - it's the container
  1440.         
  1441.         err = AECoerceDesc( container, typeMyMenu, &aDesc );
  1442.         if ( noErr != err ) goto done;
  1443.         GetRawDataFromDescriptor( &aDesc, (Ptr)&theToken,
  1444.                                         sizeof(theToken), &actualSize );
  1445.                                                             
  1446.             // get the property - it's in the selection data
  1447.         
  1448.         err = AECoerceDesc( selectionData, typeType, &propDesc );
  1449.         if ( noErr != err ) goto done;
  1450.         GetRawDataFromDescriptor( &propDesc, (Ptr)&returnedType,
  1451.                                         sizeof(returnedType), &actualSize );
  1452.         
  1453.             // Combine the two into single token
  1454.  
  1455.         thePropertyToken.token = theToken;
  1456.         thePropertyToken.tokenProperty = returnedType;
  1457.         
  1458.         err = AECreateDesc( typeMyMenuProp, (Ptr)&thePropertyToken,
  1459.                                         sizeof( thePropertyToken ), value );
  1460.     }
  1461.     
  1462. done:
  1463.     (void)AEDisposeDesc( &aDesc );
  1464.     (void)AEDisposeDesc( &propDesc );
  1465.     (void)AEDisposeDesc( &resultDesc );
  1466.         
  1467.     return(err);
  1468. } // PropertyFromMenuAccessor
  1469.  
  1470.  
  1471. OSErr    MenuItemFormAbsolutePosition( MenuToken* containerToken, const AEDesc *selectionData, AEDesc* result )
  1472. {
  1473.     AEDesc    itemDesc = {typeNull, NULL};
  1474.     short    aCount,
  1475.             index;
  1476.     OSErr    err;
  1477.  
  1478.     aCount = CountMenuTokenItems( containerToken );
  1479.     
  1480.     if (! aCount)
  1481.         return(errAEIllegalIndex);
  1482.     
  1483.     if ( typeAbsoluteOrdinal == selectionData->descriptorType )
  1484.     {
  1485.         err = noErr;
  1486.     
  1487.         switch (*(DescType *)*selectionData->dataHandle)
  1488.         {
  1489.             case kAEFirst:
  1490.                 index = 1;
  1491.                 break;
  1492.     
  1493.             case kAELast:
  1494.                 index = aCount;
  1495.                 break;
  1496.     
  1497.             case kAEMiddle:
  1498.                 index = (aCount + 1) / 2;
  1499.                 break;
  1500.     
  1501.             case kAEAny:
  1502.                 index = (Random() % aCount) + 1;
  1503.                 break;
  1504.     
  1505.             case kAEAll:
  1506.                 err = AECreateList(NULL, 0 , false, result);
  1507.                 if (noErr != err) goto done;
  1508.                 
  1509.                 for (index = 1; index <= aCount; index++)
  1510.                 {
  1511.                     err = GetDescOfNthMenuItem( containerToken, index, &itemDesc );
  1512.                     if (noErr != err) goto done;
  1513.                     
  1514.                     err = AEPutDesc(result, 0, &itemDesc);
  1515.                     if (noErr != err) goto done;
  1516.                     
  1517.                     if (itemDesc.dataHandle)
  1518.                         AEDisposeDesc(&itemDesc);
  1519.                 }
  1520.                 
  1521.                 goto done;        // We have created our list descriptor
  1522.                 break;            // so we can just tidy up and return.
  1523.                 
  1524.             default:
  1525.                 err = errAETypeError;
  1526.         }
  1527.     }
  1528.     else
  1529.         err = GetIntegerFromDescriptor( selectionData, &index );
  1530.  
  1531.     if (noErr != err) goto done;
  1532.     
  1533.     if (index < 0)        // Handle negative indexes
  1534.         index = aCount + index + 1;
  1535.         
  1536.     if ( index > aCount || index <= 0 )
  1537.         err = errAEIllegalIndex;
  1538.     else
  1539.         err = GetDescOfNthMenuItem( containerToken, index, result );
  1540.  
  1541. done:    
  1542.     (void)AEDisposeDesc( &itemDesc );
  1543.  
  1544.     return err;
  1545. } // MenuFormAbsolutePosition
  1546.  
  1547.  
  1548. OSErr    MenuItemFormName( MenuToken* containerToken, const AEDesc* selectionData, AEDesc* result )
  1549. {
  1550.     Str255        name;
  1551.     OSErr        err;
  1552.     
  1553.             // This tries to coerce it first
  1554.     err = GetPStringFromDescriptor( selectionData, name );
  1555.     if ( noErr != err ) goto done;
  1556.  
  1557.     err = GetDescOfNamedMenuItem( containerToken, name, result );
  1558.  
  1559. done:
  1560.     return(err);
  1561. }
  1562.  
  1563.  
  1564. pascal OSErr    MenuItemFromMenuAccessor( DescType            wantClass,
  1565.                                             const AEDesc    *container,
  1566.                                             DescType          containerClass,
  1567.                                             DescType        form, 
  1568.                                             const AEDesc    *selectionData,
  1569.                                             AEDesc            *value,
  1570.                                             long            theRefCon)
  1571. {
  1572. #ifdef __MWERKS__
  1573.     #pragma unused ( containerClass, theRefCon )
  1574. #endif
  1575.  
  1576.     MenuToken    containerToken;
  1577.     Size        actualSize;
  1578.     OSErr       err;
  1579.     
  1580.         // Can only handle cMenu
  1581.     if ( wantClass != cMenuItem )
  1582.         return errAEWrongDataType;
  1583.         
  1584.         // Can only handle typeMyMenu
  1585.     if ( container->descriptorType != typeMyMenu )
  1586.         return errAENoSuchObject;
  1587.  
  1588.         // Get the containing MenuToken
  1589.     GetRawDataFromDescriptor( container, (Ptr)&containerToken,
  1590.                                         sizeof( containerToken ), &actualSize );
  1591.  
  1592.     switch (form)
  1593.     {
  1594.         case formAbsolutePosition:
  1595.             err = MenuItemFormAbsolutePosition( &containerToken, selectionData, value );
  1596.             break;
  1597.             
  1598.         case formName:
  1599.             err = MenuItemFormName( &containerToken, selectionData, value );
  1600.             break;
  1601.             
  1602.         default:
  1603.             err = errAEBadTestKey;
  1604.     }
  1605.             
  1606.     return err;
  1607. }
  1608.  
  1609.  
  1610. pascal OSErr    PropertyFromMenuItemAccessor(DescType        wantClass,
  1611.                                                 AEDesc        *container,
  1612.                                                 DescType    containerClass,
  1613.                                                 DescType    form, 
  1614.                                                 AEDesc        *selectionData,
  1615.                                                 AEDesc        *value,
  1616.                                                 long        theRefCon)
  1617. {
  1618. #ifdef __MWERKS__
  1619.     #pragma unused(containerClass)
  1620. #endif
  1621.  
  1622.     long                itemCount,
  1623.                         index;
  1624.     AEDesc                resultDesc = {typeNull, NULL},
  1625.                         aDesc = {typeNull, NULL},
  1626.                         propDesc = {typeNull, NULL};
  1627.     Size                actualSize;
  1628.     DescType            returnedType;
  1629.     MenuItemToken         theToken;
  1630.     MenuItemPropToken     thePropertyToken;
  1631.     OSErr               err;
  1632.     
  1633.     if (typeAEList == container->descriptorType)
  1634.     {
  1635.         err = AECreateList( NULL, 0 , false, value );    // Result will also be a list of items
  1636.         if ( noErr != err ) goto done;
  1637.         err = AECountItems( container, &itemCount );
  1638.         if ( noErr != err ) goto done;
  1639.     
  1640.         for ( index = 1; index <= itemCount; index++ )    // Do in forward order
  1641.         {
  1642.             err = AEGetNthDesc( container, index, typeWildCard, &returnedType, &aDesc );
  1643.             if ( noErr != err ) goto done;
  1644.                                                         // Recursively call this routine
  1645.                                                         // - could be another list.
  1646.             err = PropertyFromMenuItemAccessor( wantClass, &aDesc, aDesc.descriptorType,
  1647.                                                 form, selectionData, &resultDesc, theRefCon );
  1648.             if ( noErr != err ) goto done;
  1649.                                                     
  1650.             err = AEPutDesc( value, 0, &resultDesc );    // Add item to the end of our list
  1651.             if ( noErr != err ) goto done;
  1652.             
  1653.             (void)AEDisposeDesc( &aDesc );
  1654.             (void)AEDisposeDesc( &resultDesc );
  1655.         }
  1656.     }
  1657.     else
  1658.     {
  1659.         err = AECoerceDesc(container, typeMyMenuItem, &aDesc);
  1660.         if ( noErr != err ) goto done;
  1661.         GetRawDataFromDescriptor(&aDesc, (Ptr)&theToken,
  1662.                                         sizeof(theToken), &actualSize);
  1663.                                                             
  1664.             // get the property - it's in the selection data
  1665.         
  1666.         err = AECoerceDesc( selectionData, typeType, &propDesc );
  1667.         if ( noErr != err ) goto done;
  1668.         GetRawDataFromDescriptor( &propDesc, (Ptr)&returnedType,
  1669.                                         sizeof(returnedType), &actualSize );
  1670.         
  1671.             // Combine the two into single token
  1672.  
  1673.         thePropertyToken.token = theToken;
  1674.         thePropertyToken.tokenProperty = returnedType;
  1675.         
  1676.         err = AECreateDesc( typeMyMenuItemProp, (Ptr)&thePropertyToken,
  1677.                                         sizeof( thePropertyToken ), value );
  1678.     }
  1679.     
  1680. done:
  1681.     (void)AEDisposeDesc(&aDesc);
  1682.     (void)AEDisposeDesc(&propDesc);
  1683.     (void)AEDisposeDesc(&resultDesc);
  1684.         
  1685.     return(err);
  1686. } // PropertyFromMenuItemAccessor
  1687.  
  1688.